const fs = require('fs')
const path = require('path')
const yaml = require('js-yaml')

const pathRoot = path.join(__dirname, '../../content')

const DEFAULT_AUTHOR = '南川'
const DEFAULT_LANG = 'zh'
const LANG_LIST = ['zh', 'en']
const TARGET_FILETYPE_LIST = ['.md']
const INDEX_FILENAME_LIST = ['index.md', 'readme.md']

// String.prototype.hashcode = function () {
//   return this.split('')
//     .map((v) => v.charCodeAt(0))
//     .reduce((a, v) => (a + ((a << 7) + (a << 3))) ^ v)
//     .toString(16)
// }

Object.defineProperty(String.prototype, 'hashCode', {
  value: function () {
    var hash = 0,
      i,
      chr
    for (i = 0; i < this.length; i++) {
      chr = this.charCodeAt(i)
      hash = (hash << 5) - hash + chr
      hash |= 0 // Convert to 32bit integer
    }
    return hash
  },
})

const cyrb53 = function (str, seed = 0) {
  let h1 = 0xdeadbeef ^ seed,
    h2 = 0x41c6ce57 ^ seed
  for (let i = 0, ch; i < str.length; i++) {
    ch = str.charCodeAt(i)
    h1 = Math.imul(h1 ^ ch, 2654435761)
    h2 = Math.imul(h2 ^ ch, 1597334677)
  }
  h1 =
    Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^
    Math.imul(h2 ^ (h2 >>> 13), 3266489909)
  h2 =
    Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^
    Math.imul(h1 ^ (h1 >>> 13), 3266489909)
  return 4294967296 * (2097151 & h2) + (h1 >>> 0)
}

const isIndexFile = (fn) => INDEX_FILENAME_LIST.includes(fn.toLowerCase())
const getFileName = (fn) => fn.substring(0, fn.lastIndexOf('.'))
const getFileType = (fn) =>
  /\./.test(fn) ? fn.substring(fn.lastIndexOf('.')) : null
const isTargetFileType = (fn) => TARGET_FILETYPE_LIST.includes(getFileType(fn))

function genFileList(relPathBase, list = []) {
  console.log('scanning relative path: ', relPathBase)
  fs.readdirSync(path.join(pathRoot, relPathBase), {
    withFileTypes: true,
  }).forEach((file) => {
    const relPathBaseNew = path.join(relPathBase, file.name)
    if (file.isDirectory()) {
      genFileList(relPathBaseNew, list)
    } else if (isTargetFileType(file.name)) {
      const item = {
        relativePath: path.join(relPathBase, file.name).replace(/\\/g, '/'),
        dirName: path.basename(relPathBase),
        fileName: getFileName(file.name),
      }
      list.push(item)
    }
  })
  return list
}

function parseFrontMatter(pathRoot, fp) {
  console.log('parsing file: ', fp)
  const c = fs.readFileSync(path.join(pathRoot, fp), 'utf-8', String)
  if (!/^---/.test(c)) throw new Error('missing frontmatter')

  if (!/^---\r?\n.*?^---\r?\n\r?\n/ms.test(c))
    throw new Error('illegal' + ' frontmatter format')

  const m = c.match(/^---\r?\n(.*?)^---\r?\n\r?\n/ms)
  const y = yaml.safeLoad(m[1]) || {}

  function getTitle(c, y, fp) {
    if (/^# (.*?)$/m.test(c)) return c.match(/^# (.*?)$/m)[1]
    else if (y.mdTitle) return y.mdTitle
    else if (y.title) return y.title
    else return getFileName(path.basename(fp))
  }

  function getMenuTitle(c, y, fp) {
    return y.menuTitle || getTitle(c, y, fp)
  }

  function getDate(c, y, fp) {
    const DATE_COMPILE = /(\d{4}).?(\d{2}).?(\d{2})/
    function matchDate(value) {
      // console.log({ value })
      if (DATE_COMPILE.test(value)) {
        const m = value.match(DATE_COMPILE)
        return `${m[1]}-${m[2]}-${m[3]}`
      } else {
        throw new Error('illegal date format: ', value)
      }
    }

    if (y.date) {
      if (y.date instanceof Date) {
        return [
          `${y.date.getFullYear()}`,
          `${y.date.getMonth() + 1}`.padStart(2, '0'),
          `${y.date.getDate()}`.padStart(2, 0),
        ].join('-')
      }
      return matchDate(y.date)
    }
    if (DATE_COMPILE.test(path.basename(fp)))
      return matchDate(path.basename(fp))
    // todo: 加入操作系统文件创建日期的选项
    return null
  }

  function getID(c, y, fp) {
    if (y.ID) return y.ID
    return cyrb53(
      fp
        .split('/')
        .filter((x) => x !== '')
        .slice(1)
        .join('/')
    )
  }

  function getTags(c, y, fp, trimFirst = true) {
    if (y.tags) {
      if (!y.tags instanceof Array)
        throw new Error('illegal tags format: ', y.tags)
      return y.tags
    }
    const dirs = fp
      .replace(/\\/g, '/')
      .split('/')
      .filter((s) => s !== '')
    // todo: 要判断是否包含语言路径
    return dirs.slice(Number(trimFirst), dirs.length - 1)
  }

  function getDescription(c, y, fp, maxLength = 100) {
    var desc = y.description || y.desc || ''
    // todo: 这里要使用markdown渲染后的第一个p节点
    return desc.substr(0, maxLength)
  }

  function getAuthor(c, y, fp) {
    if (y.author) return y.author
    return DEFAULT_AUTHOR
  }

  var f = {
    id: getID(c, y, fp),
    title: getTitle(c, y, fp),
    menuTitle: getMenuTitle(c, y, fp),
    date: getDate(c, y, fp),
    tags: getTags(c, y, fp),
    description: getDescription(c, y, fp),
    author: getAuthor(c, y, fp),
  }

  // console.log({ y, f })
  return f
}

function exportNav(item) {
  const keys = ['id', 'title', 'menuTitle', 'tags', 'description']
  let d = {}
  keys.map((key) => (d[key] = item[key]))
  return d
}

const navList = genFileList('/zh')
let navMap = {}
navList.map((item) => parseFrontMatter(pathRoot, item.relativePath))
// .map(exportNav)
// .map((item) => (navMap[item.id] = item))
// fs.writeFileSync('menus.json', JSON.stringify(navMap, null, 2))
console.log(navList, navMap)
